#ifndef INTER_HEAD
#define INTER_HEAD
#include "lexer.hpp"
#include <iostream>
class Node{//抽象语法树中的节点类，用于报告错误
public:
    int lexline;
    Node():lexline(Lexer::line){}
    static int labels;
    void error(string s){
        throw("near line"+std::to_string(lexline)+": "+s);
    }
    int newlabels(){return labels++;}
    void emitlabel(int i){
        std::cout<<"L"<<i<<":";
    }
    void emit(string s){
        std::cout<<"\t"<<s<<std::endl;
    }
};
int Node::labels = 0;

class Expr:public Node{//包含字段 op 和 type 
public:
    Token op;
    Type type;
    Expr(Token tok=Token(),Type p=Type()):op(tok),type(p){}
    virtual Expr& gen(){
        return *this;
    }
    virtual Expr& reduce(){
        return *this;
    }
    void jumping(int t,int f){
        emitjumps(string(""),t,f);
    }
    void emitjumps(string s,int t,int f){
        if(t&&f){
            emit(string("if ")+s+" goto L"+std::to_string(t));
            emit(string("goto L")+std::to_string(f));
        }
        else if(t)emit(string("if ")+s+" goto L"+std::to_string(t));
        else if(f)emit(string("iffalse "+s+" goto L"+std::to_string(f)));
        else ;
    }
    string toString(){return op.toString();}

private:
};
class Id :public Expr{
public:
    int offset;//相对地址
    Id(Word id,Type p,int b):Expr(id,p),offset(b){}
};

class Temp:public Expr{
public:
    static int count ;
    int number;
    Temp(Type p ):Expr(Word::Temp,p),number(++count){}
    string toString(){return string("t")+std::to_string(number);}
};
int Temp::count = 0;

class Op:public Expr{
public:
    Op(Token tok,Type p):Expr(tok,p){}
    Expr& reduce(){
        Expr x = gen();
        Temp t(type);
        emit(t.toString()+" = "+x.toString());
        return t;
    }
};

class Arith:public Op{                      //处理两目运算符 expr1 op expr2
public:

    Expr expr1,expr2;

    Arith(Token tok=Token(),Expr x1=Expr(),Expr x2=Expr()):Op(tok,Type::Operator),expr1(x1),expr2(x2){
        try{
            type = max(x1.type,x2.type);
        }
        catch(const char*info){
            std::cout<<info<<"\n"<<"In file inter.hpp line 86. Type Error!"<<std::endl;
        }
    }
    Expr& gen(){
        return *(new Arith(op,expr1.reduce(),expr2.reduce()));
    }
    string toString(){
        return expr1.toString()+" "+op.to_string()+" "+expr2.toString();
    }
private:

};
class Unary:public Op{
public:
    Expr expr;
    Unary(Token tok=Token(),Expr x=Expr()):Op(tok,Type::Operator),expr(x){
        try{
            type = max(Type::Int,x.type);
        }
        catch(const char*info){
            std::cout<<info<<"\n"<<"In file inter.hpp line 106. Type Error!"<<std::endl;
        }
    }
    Expr& gen(){
        return *(new Unary(op,expr.reduce()));
    }
    string toString(){
        return op.toString()+" "+expr.toString();
    }

private:

};

class Constant:public Expr{
public:
    Constant(Token tok,Type p):Expr(tok,p){}
    Constant(int i):Expr(Num(i),Type::Int){}
    static const Constant True,False;
    void jumping(int t,int f){
        if(((*this) == True)&&t!=0)emit(string("goto L")+std::to_string(t));
        else if(((*this)==False)&&f!=0)emit(string("goto L")+std::to_string(f));
    }


private:
    bool operator==(const Constant& con){
        return con.lexline==lexline&&con.type==type&&con.op==op;
    }

};

#endif